/*
 * File : command.c
 *
 */

#include "config.h"
#include "memory.h"
#include "command.h"
#include "xstring.h"
#include "message.h"
#include "spi_flash.h"
#include "flash_mem.h"
#include "task.h"
#include "tool.h"
#include <stdlib.h>
#include <stdio.h>

#include "command_data.h"
#include "main.h"

extern void Initial_App_Task(void);

unsigned char input_port;

/* function prototype */
static void Load_Sys_Default_Task(void);

static int cmpstr(const char *str1, const char *str2)
{
	register unsigned char ret;

	while (*str1)
	{
		ret = *str1++ - *str2++;
		if ((ret != 0) && (ret != 0x20))
		{
			break;
		}
	}

	if (ret == 0x20)
	{
		ret = 0;
	}

	return ret;
}

static int check_ip(char *buf)
{
	char ip[4];
	char num = 0;
	int i, j, k;

	for(i = 0, j = 0; i < 16; i++)
	{
		if((buf[i] == '.') || (buf[i] == '\0'))
		{
			ip[j] = '\0';
			j = 0;
			num++;
			k = xatoi(ip);
			if ((k > 255) || (k < 0))
				return -1;
			if (buf[i] == '\0')
				break;
		}
		else
		{
			ip[j++] = buf[i];
		}

		if (j == 4)
			return -1;
	}

	if (num == 3)
	{
		num++;
		k = xatoi(ip);
		if ((k > 255) || (k < 0))
		{
			return -1;
		}
	}

	if (num == 4)
	{
		return 0;
	}
	else
	{
		return -1;
	}
}

static int CMD_Question_Mark(unsigned char idx, void *buf, void *out)
{
	const char *type;
	char *ptr;
	int i;
	unsigned char item;
	unsigned short int16;
	unsigned long int32;
	unsigned long long int64;
	double dou;
	char *temp;

	temp	= (char *)malloc(sizeof(char) * 256);
	assert_malloc(temp);
	ptr		= (char *)buf;

	for (i = 1; i <= CMD_Decoder[idx].para.num; i++)
	{
		if (xstrlen(out) > 350)
		{
			Msg_Write(input_port, out, AT_CMD_RESPONSE);
			*((char *)out) = '\0';
		}

		if (i != 1)
		{
			xstrcat(out, "\r\n");
		}

		type	= CMD_Decoder[idx].para.type_string;
		item	= 0;

		if (CMD_Decoder[idx].para.num == 1)
		{
			sprintf(temp, "$%s=", CMD_Decoder[idx].para.code);
		}
		else
		{
			sprintf(temp, "$%s=%d", CMD_Decoder[idx].para.code, i);
		}

		xstrcat(out, temp);

		while(*type != '\0')
		{
			if (item != 0)
			{
				xstrcat(out, ",\0");
			}

			switch (*type)
			{
			default:
			case CMD_TYPE_IGNORE:
					xstrcat(out, "0\0");
				break;
			case CMD_TYPE_INT_1:
				sprintf(temp, "%d", (unsigned char)*ptr);
				xstrcat(out, temp);
				ptr++;
				break;
			case CMD_TYPE_SIGN_1:
				sprintf(temp, "%d", (char)*ptr);
				xstrcat(out, temp);
				ptr++;
				break;
			case CMD_TYPE_INT_2:
				xmemcpy(&int16, (void *)ptr, 2);
				sprintf(temp, "%d", int16);
				xstrcat(out, temp);
				ptr += 2;
				break;
			case CMD_TYPE_INT_4:
				xmemcpy(&int32, (void *)ptr, 4);
				sprintf(temp, "%d", int32);
				xstrcat(out, temp);
				ptr += 4;
				break;
			case CMD_TYPE_INT_8:
				xmemcpy(&int64, (void *)ptr, 8);
				sprintf(temp, "%llu", int64);
				xstrcat(out, temp);
				ptr += 8;
				break;
			case CMD_TYPE_DOUBLE:
				xmemcpy(&dou, (void *)ptr, 8);
				sprintf(temp, "%.5f", dou);
				xstrcat(out, temp);
				ptr += 8;
				break;
			case CMD_TYPE_PHONE:
			case CMD_TYPE_NUM_STR:
			case CMD_TYPE_HEX_STR:
			case CMD_TYPE_IP:
			case CMD_TYPE_STRING:
				xmemcpy(temp, (void *)ptr, CMD_Decoder[idx].limit[item].max + 1);
				xstrcat(out, temp);
				ptr += (CMD_Decoder[idx].limit[item].max + 1);
				break;
			case CMD_TYPE_IDX:
				ptr = (char *)buf + ((i - 1) * CMD_Decoder[idx].para.offset);
				break;
			}

			type++;
			item++;
		}
	}

	free(temp);
	assert_free();
	xstrcat(out, "\r\n\0");
	Msg_Write(input_port, out, AT_CMD_RESPONSE);
	return 0;
}

/**
 * @brief	Process AT$CMD=...
 * @param	idx			idx of command decode table
 * @param	input_buf	ex: "AT$modid=1234,abcd" input_buf: "1234,abcd"
 * @param	outupt_buf	storage command parameter
 * @return	none
 * @note
 */
static int CMD_Equals_Sign(unsigned char idx, char *input_buf, void *output_buf)
{
	const char *type;	//point to command type_string
	char *ptr;			//output buffer pointer
	char *buf;			//
	char *tempbuf;		//output temp buffer
	char *temp;
	unsigned char tempidx = 0;	//output temp buffer index
	unsigned char sum;
	int len;
	unsigned long int32;
	char item;	//record item number

	type	= CMD_Decoder[idx].para.type_string;

	if (type == NULL)
	{
		/* execute function */
		if (*CMD_Decoder[idx].para.fun != NULL)
		{
			(*CMD_Decoder[idx].para.fun)(input_buf);
		}

		return 0;
	}

	buf		= (char *)malloc(sizeof(char) * 256);
	assert_malloc(buf);
	tempbuf	= (char *)malloc(sizeof(char) * 256);
	assert_malloc(tempbuf);
	item	= 0;
	ptr		= output_buf;
	xmemset(tempbuf, 0, 256);

	while(*type != '\0')
	{
		if (*type != CMD_TYPE_IGNORE)
		{
			GetStringItem(input_buf, buf, item);
		}

		switch (*type)
		{
		default:
		case CMD_TYPE_IGNORE:
			break;
		case CMD_TYPE_SIGN_1:
		case CMD_TYPE_INT_1:
			if (xstrlen(buf) == 0)
			{
				tempbuf[tempidx] = *ptr;
			}
			else
			{
				len = xatoi(buf);

				if ((len < CMD_Decoder[idx].limit[item].min) ||
					(len > CMD_Decoder[idx].limit[item].max))
				{
					goto ERR;
				}

				tempbuf[tempidx] = (char)len;
			}

			tempidx++;
			ptr++;
			break;
		case CMD_TYPE_INT_2:
			if (xstrlen(buf) == 0)
			{
				xmemcpy((void *)&tempbuf[tempidx], (void *)ptr, 2);
			}
			else
			{
				unsigned short int16;

				len = xatoi(buf);
				if ((len < CMD_Decoder[idx].limit[item].min) ||
					(len > CMD_Decoder[idx].limit[item].max))
				{
					goto ERR;
				}

				int16 = (unsigned short)len;
				xmemcpy((void *)&tempbuf[tempidx], (void *)&int16, 2);
			}

			ptr		+= 2;
			tempidx	+= 2;
			break;
		case CMD_TYPE_INT_4:
			if (xstrlen(buf) == 0)
			{
				xmemcpy((void *)&tempbuf[tempidx], (void *)ptr, 4);
			}
			else
			{
				len = xatoi(buf);
				int32 = (unsigned long)len;
				xmemcpy((void *)&tempbuf[tempidx], (void *)&int32, 4);
			}

			ptr		+= 4;
			tempidx	+= 4;
			break;
		case CMD_TYPE_INT_8:
			if (xstrlen(buf) == 0)
			{
				xmemcpy((void *)&tempbuf[tempidx], (void *)ptr, 8);
			}
			else
			{
				unsigned long long  int64, temp64;

				int64	= xatoll(buf);
				temp64	= int64;
				for (len = 0; temp64 != 0; len++, temp64 /= 10)
					;

				if ((len < CMD_Decoder[idx].limit[item].min) ||
					(len > CMD_Decoder[idx].limit[item].max))
				{
					goto ERR;
				}

				xmemcpy((void *)&tempbuf[tempidx], (void *)&int64, 8);
			}

			ptr		+= 8;
			tempidx	+= 8;
			break;
		case CMD_TYPE_DOUBLE:
			if (xstrlen(buf) == 0)
			{
				xmemcpy((void *)&tempbuf[tempidx], (void *)ptr, 8);
			}
			else
			{
				double dou;

				dou	= atof(buf);
				if ((dou < (CMD_Decoder[idx].limit[item].min * -1)) ||
					(dou > CMD_Decoder[idx].limit[item].max))
				{
					goto ERR;
				}

				xmemcpy((void *)&tempbuf[tempidx], (void *)&dou, 8);
			}

			ptr		+= 8;
			tempidx	+= 8;
			break;
		case CMD_TYPE_NUM_STR:
			if (Chk_Num_String(buf) == 0)
			{
				goto STRING;
			}
			else
			{
				goto ERR;
			}
		case CMD_TYPE_STRING:
STRING:
			len	= xstrlen(buf);

			if (len == 0)
			{
				xmemcpy((void *)&tempbuf[tempidx], (void *)ptr,
							CMD_Decoder[idx].limit[item].max + 1);
			}
			else
			{
				if (cmpstr(buf, "NULL") != 0)
				{
					if ((len < CMD_Decoder[idx].limit[item].min) ||
						(len > CMD_Decoder[idx].limit[item].max))
					{
						goto ERR;
					}

					xmemcpy((void *)&tempbuf[tempidx], buf, len + 1);
				}
			}

			ptr		+= (CMD_Decoder[idx].limit[item].max + 1);
			tempidx	+= (CMD_Decoder[idx].limit[item].max + 1);
			break;
		case CMD_TYPE_IDX:
			len = xatoi(buf);

			if ((len < CMD_Decoder[idx].limit[item].min) ||
				(len > CMD_Decoder[idx].limit[item].max))
			{
				goto ERR;
			}

			len = (len - 1) * CMD_Decoder[idx].para.offset;
			ptr += len;
			output_buf = (void *)ptr;
			break;
		case CMD_TYPE_PHONE:
			temp = buf;

			if (*buf == '+')
			{
				temp++;
			}

			if (cmpstr(buf, "NULL") == 0)
			{
				goto STRING;
			}

			if (Chk_Num_String(temp) == 0)
			{
				goto STRING;
			}
			else
			{
				goto ERR;
			}
		case CMD_TYPE_IP:
			len	= xstrlen(buf);

			if (len == 0)
			{
				xmemcpy((void *)&tempbuf[tempidx], (void *)ptr,
							CMD_Decoder[idx].limit[item].max + 1);
			}
			else
			{
				if (cmpstr(buf, "NULL") == 0)
				{
					goto STRING;
				}

				if (check_ip(buf) != 0)
				{
					goto ERR;
				}

				xmemcpy((void *)&tempbuf[tempidx], buf, len + 1);
			}

			ptr		+= (CMD_Decoder[idx].limit[item].max + 1);
			tempidx	+= (CMD_Decoder[idx].limit[item].max + 1);
			break;
		}

		item++;
		type++;
	}

	sum = Calc_CheckSum(output_buf, (unsigned short)tempidx);
	pCMD->checksum ^= sum;
	xmemcpy(output_buf, (void *)&tempbuf[0], tempidx);
	sum = Calc_CheckSum(&tempbuf[0], tempidx);
	pCMD->checksum ^= sum;
	int32 = USER_TBL_ADDR + ((unsigned long)output_buf - (unsigned long)pCMD);
    //fenris 20110303 ==start==
    SPI_FLASH_PageErase(USER_TBL_ADDR);
    //SPI_Flash_Write(USER_TBL_ADDR, &pCMD, (int32-USER_TBL_ADDR));
    //SPI_Flash_Write(int32, output_buf, tempidx);
    //SPI_Flash_Write((int32+tempidx), &(pCMD+int32+tempid-USER_TBL_ADDR), (sizeof(pCMD)-tempidx-int32+USER_TBL_ADDR))
    //xmemcpy(&pCMD+int32-USER_TBL_ADDR, output_buf, tempidx);
    SPI_Flash_Write(USER_TBL_ADDR, (unsigned char*)pCMD, sizeof(CMD_DATA));
    //fenris 20110303 ===end===
//	SPI_Flash_Write(int32, output_buf, tempidx);
	SPI_Flash_Wait_Ready();
	int32 = USER_TBL_ADDR + sizeof(CMD_DATA) - 11;
//	SPI_Flash_Write(int32, &pCMD->checksum, 1);
	sprintf(buf, "OK:%s", CMD_Decoder[idx].para.code);
	Msg_Res_Write(input_port, buf);
	free(buf);
	assert_free();
	free(tempbuf);
	assert_free();
	return 0;
ERR:
	sprintf(buf, "ERROR:%s", CMD_Decoder[idx].para.code);
	Msg_Res_Write(input_port, buf);
	free(buf);
	assert_free();
	free(tempbuf);
	assert_free();
	return -1;
}

/**
 * @brief	Decode Command
 * @param	buf		ex."at$modid=1234,abcd" buf :"modid=1234,abcd"
 * @return	none
 * @note
 */
static int CMD_Para_Decode(char *buf)
{
	int i;
	char cmd[11];
	char *ptr;
	char *output;

	ptr = (char *)pCMD;
	i	= 0;
	/* GET Command, AT$CMD=..., AT$CMD?, AT$CMD */
	while ((*buf != '=') && (*buf != '?') && (*buf != '\0'))
	{
		cmd[i++] = xtoupper(*buf++);
		if (i > 10)
		{
			/* prevent error */
			i = 0;
		}
	}
	/* cmd[] = "CMD" */
	cmd[i] = '\0';

	/* Search Command Table */
	for (i = 0;;)
	{
		if (xstrcmp(CMD_Decoder[i].para.code, cmd) == 0)
		{
			/* Command Match */
			if ((*buf == '=') && (CMD_Decoder[i].para.attribute & EQUAL))
			{
				/* AT$CMD=..." */
				CMD_Equals_Sign(i, (char *)++buf, (void *)ptr);

				if ((CMD_Decoder[i].para.type_string != NULL) && !(CMD_Decoder[i].para.attribute & EXECUTE))
				{
					if (*CMD_Decoder[i].para.fun != NULL)
					{
						(*CMD_Decoder[i].para.fun)(NULL);
					}
				}
			}
			else if ((*buf == '?') && (CMD_Decoder[i].para.attribute & QUESTION))
			{
				/* AT$CMD? */
				output = (char *)malloc(sizeof(char) * 512);
				assert_malloc(output);
				sprintf(output, "OK:%s\r\n", CMD_Decoder[i].para.code);
				Msg_Write(input_port, output, AT_CMD_RESPONSE);
				output[0] = '\0';
				CMD_Question_Mark(i, (void *)ptr, output);
				free(output);
				assert_free();
			}
			else if ((*buf == '\0') && (CMD_Decoder[i].para.attribute & EXECUTE))
			{
				/* AT$CMD */
				if (*CMD_Decoder[i].para.fun != NULL)
				{
					output = (char *)malloc(sizeof(char) * 512);
					assert_malloc(output);
					sprintf(output, "OK:%s\r\n", CMD_Decoder[i].para.code);
					Msg_Write(input_port, output, AT_CMD_RESPONSE);
					output[0] = '\0';
					(*CMD_Decoder[i].para.fun)(output);
					free(output);
					assert_free();
				}
			}
			else
			{
				Msg_Write(input_port, "ERROR:UNKNOW\r\n", AT_CMD_RESPONSE);
			}

			break;
		}
		else
		{
			ptr += (CMD_Decoder[i].para.offset * CMD_Decoder[i].para.num);
		}

		i++;

		if (i == Get_num_cmd())
		{
			Msg_Write(input_port, "ERROR:UNKNOW\r\n", AT_CMD_RESPONSE);
			break;
		}
	}
	return 0;
}

/* Parser STATE define */
typedef enum {
	CMD_STATE_START 	= 0,
	CMD_STATE_A			= 1,
	CMD_STATE_AT		= 2,
	CMD_STATE_ATI		= 3,
	CMD_STATE_ATAND		= 4,
	CMD_STATE_ATANDV	= 5,
	CMD_STATE_ATANDF	= 6,
	CMD_STATE_ATM		= 7,
	CMD_STATE_ATC		= 8,
	CMD_STATE_END		= 9
}CMD_STATE;

static CMD_STATE CMD_State;

static void CMD_Start(char *buf)
{
	/* Wait 'A' */
	*buf = xtoupper(*buf);

	if (*buf == 'A')
	{
		/* buf = "A..." */
		CMD_State = CMD_STATE_A;
	}
}

static void CMD_A(char *buf)
{
	/* Wait 'T' */
	*buf = xtoupper(*buf);

	if (*buf == 'T')
	{
		/* buf = "AT...." */
		CMD_State = CMD_STATE_AT;
	}
	else
	{
		/* Not "AT", return start */
		CMD_State = CMD_STATE_START;
	}
}

static void CMD_AT(char *buf)
{
	/* AT$... is ST Protocol */
	*buf = xtoupper(*buf);

	if (*buf == '$')
	{
		/* buf = "AT$..." */
		CMD_State = CMD_STATE_ATC;
	}
	else if (*buf == 'I')
	{
		/* buf = "ATI..." */
		CMD_State = CMD_STATE_ATI;
	}
	else if (*buf == '&')
	{
		/* buf = "AT&..." */
		CMD_State = CMD_STATE_ATAND;
	}
	else
	{
		/* other protocol */
		if (*pFlag_modem_pt == 1)
		{
			/* pass through modem */
//			GSM_Write("AT", 2);         //fenris 20110302 mark
//			GSM_Write(buf, 1);

			if (*buf == ASC_CR)
			{
//				GSM_Write("\n", 1);
				CMD_State = CMD_STATE_START;
			}
			else
			{
				CMD_State = CMD_STATE_ATM;
			}
		}
		else
		{
			CMD_State = CMD_STATE_START;
		}
	}
}

static void CMD_ATI(char *buf)
{
	char *pbuf;

	if (*buf == '\0')
	{
		Msg_Write(input_port, "OK:ATI\r\n\0", AT_CMD_RESPONSE);
		pbuf = (char *)malloc(sizeof(char) * 512);
		assert_malloc(pbuf);
        sprintf(pbuf, "%s\r\nHardware version %s\r\nFirmware version %s%s\r\n", //MCU flash size %dK\r\nMCU ram size %dK\r\n",
				BRAND_NAME, HW_VERSION, FW_VERSION, FW_REVISED);    //, MCU_flash_size, MCU_ram_size);
		Msg_Write(input_port, pbuf, AT_CMD_RESPONSE);
		free(pbuf);
		assert_free();
	}

	CMD_State = CMD_STATE_START;
}

static void CMD_ATAND(char *buf)
{
	*buf = xtoupper(*buf);

	if (*buf == 'V')
	{
		CMD_State = CMD_STATE_ATANDV;
	}
	else if (*buf == 'F')
	{
		CMD_State = CMD_STATE_ATANDF;
	}
	else
	{
		CMD_State = CMD_STATE_START;
	}
}

static void CMD_ATANDV(char *buf)
{
	int i;
	char *ptr;
	char *pbuf;

	ptr = (char *)pCMD;

	if (*buf == '\0')
	{
		Msg_Write(input_port, "OK:AT&V\r\n\0", AT_CMD_RESPONSE);

		pbuf = (char *)malloc(sizeof(char) * 1024);
		assert_malloc(pbuf);

		for (i = 0; i < Get_num_cmd(); i++)
		{
			if (CMD_Decoder[i].para.attribute & QUESTION)
			{
				pbuf[0] = '\0';
				CMD_Question_Mark(i, (void *)ptr, pbuf);
			}

			ptr += (CMD_Decoder[i].para.offset * CMD_Decoder[i].para.num);
		}

		free(pbuf);
		assert_free();
	}

	CMD_State = CMD_STATE_START;
}

static void CMD_ATANDF(char *buf)
{
	if (*buf == '\0')
	{
		if (SPI_Flash_Wait_Ready() == SPI_FLASH_OK)
		{
			Reset_Sys_Default_Value();
			SPI_Flash_Write(USER_TBL_ADDR, (unsigned char *)pCMD, sizeof(CMD_DATA));
			SPI_Flash_Write(DEFAULT_TBL_ADDR, (unsigned char *)pCMD, sizeof(CMD_DATA));
			Msg_Write(input_port, "OK:AT&F\r\n\0", AT_CMD_RESPONSE);
		}
	}

	CMD_State = CMD_STATE_START;
}

static void CMD_ATM(char *buf)
{
	/* pass through modem */
	*buf = xtoupper(*buf);
	if (*pFlag_modem_pt == 1)
	{
//		GSM_Write(buf, 1);
	}

	if (*buf == '\0')
	{
		if (*pFlag_modem_pt == 1)
		{
//			GSM_Write("\r\n", 2);
		}

		CMD_State = CMD_STATE_START;
	}
}
static void CMD_ATC(char *buf)
{
	/* ST protocol */
	CMD_Para_Decode(buf);
	CMD_State = CMD_STATE_END;
}

static void (*CMD_STATE_Parser[])(char *buf) =
{
	CMD_Start,
	CMD_A,
	CMD_AT,
	CMD_ATI,
	CMD_ATAND,
	CMD_ATANDV,
	CMD_ATANDF,
	CMD_ATM,
	CMD_ATC,
};


/**
 * @brief	ST Command Parser
 * @param	port	source SMS/GPRS/CONSOLE
 * @param	buf		command string
 * @param	count	length of command string
 * @return	none
 * @note
 */
void CMD_Parser(unsigned char port, char *buf, unsigned short count)
{
	unsigned short i = 0;

	/* record input port for response */
	input_port = port;

	/* start parse */
	while ((CMD_State != CMD_STATE_END) && (i < count))
	{
		(*CMD_STATE_Parser[CMD_State])(buf++);
		i++;
	}
	/* end, clean status */
	CMD_State = CMD_STATE_START;
}

static void Load_Sys_Default_Task(void)
{
	if (SPI_Flash_Wait_Ready() == SPI_FLASH_OK)
	{
		Reset_Sys_Default_Value();
        SPI_FLASH_PageErase(DEFAULT_TBL_ADDR);  //fenris 20110303
		SPI_Flash_Write(DEFAULT_TBL_ADDR, (unsigned char *)pCMD, sizeof(CMD_DATA));
		TaskDel(Load_Sys_Default_Task);
		TaskAdd(Load_Cmd_Data_Task, (SYS_TICK / SYS_TICK));
	}
}

static void Load_Default_Task(void)
{
	unsigned char sum;

	if (SPI_Flash_Wait_Ready() == SPI_FLASH_OK)
	{
		SPI_Flash_Read(DEFAULT_TBL_ADDR, (unsigned char *)pCMD, sizeof(CMD_DATA));

		if(SPI_Flash_Wait_Ready() == SPI_FLASH_OK)
		{
			sum = Calc_CheckSum((char *)pCMD, (sizeof(CMD_DATA) - 11));

			if (pCMD->checksum != sum)
			{
				TaskDel(Load_Default_Task);
				TaskAdd(Load_Sys_Default_Task, (SYS_TICK / SYS_TICK));
			}
			else
			{
                SPI_FLASH_PageErase(USER_TBL_ADDR);  //fenris 20110303
				SPI_Flash_Write(USER_TBL_ADDR, (unsigned char *)pCMD, sizeof(CMD_DATA));
				TaskDel(Load_Default_Task);
				TaskAdd(Load_Cmd_Data_Task, (SYS_TICK / SYS_TICK));
			}
		}
	}
}


void Load_Cmd_Data_Task(void)
{
	unsigned char buf1[12];
	unsigned long addr1;
	unsigned short len;
	unsigned char sum;

	if (*pFlag_err_flash == 1)
	{
		*pFlag_sys_para_rdy = 1;
		Reset_Sys_Default_Value();
		goto OUT;
	}

	if (SPI_Flash_Wait_Ready() == SPI_FLASH_OK)
	{
		xmemcpy((void *)pCMD->ver, PROTOCOL_VERSION, 10);
		len		= sizeof(CMD_DATA);

		addr1	= DEFAULT_TBL_ADDR + len - 10;
		/* get PARA_VER */
		SPI_Flash_Read(addr1, buf1, 10);

		if (SPI_Flash_Wait_Ready() != SPI_FLASH_OK)
		{
			goto OUT;
		}

		if (xstrcmp((char *)buf1, (char *)pCMD->ver) != 0)
		{
			/* Default Table Version Err, Load System Default Table */
			TaskAdd(Load_Sys_Default_Task, (SYS_TICK / SYS_TICK));
			goto OUT;
		}

		addr1	= USER_TBL_ADDR + len - 10;
		SPI_Flash_Read(addr1, buf1, 10);

		if (SPI_Flash_Wait_Ready() != SPI_FLASH_OK)
		{
			goto OUT;
		}

		if (xstrcmp((char *)buf1, (char *)pCMD->ver) != 0)
		{
			/* User Table Error, Copy default to user */
			TaskAdd(Load_Default_Task, (SYS_TICK / SYS_TICK));
			goto OUT;
		}

		SPI_Flash_Read(USER_TBL_ADDR, (unsigned char *)pCMD, len);

		if (SPI_Flash_Wait_Ready() != SPI_FLASH_OK)
		{
			goto OUT;
		}

		sum = Calc_CheckSum((char *)pCMD, (len - 11));

		if (pCMD->checksum != sum)
		{
			/* Copy default to user */
			TaskAdd(Load_Default_Task, (SYS_TICK / SYS_TICK));
			goto OUT;
		}

		*pFlag_sys_para_rdy = 1;	//parameter OK
        TaskAdd(Param_Check_Task, 100);
OUT:
		TaskDel(Load_Cmd_Data_Task);
	}
}